package com.java.sample.encrypt.ecdh;

import java.io.ByteArrayOutputStream;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.ECPublicKeySpec;
import java.util.Arrays;
import java.util.Base64;

public class WebEcdhUtils {
    /**
     * 将标准PKCS#8公钥转换为非压缩格式
     * @param publicKey 标准公钥
     * @return 非压缩格式公钥的Base64字符串
     */
    public static String getUncompressedPublicKey(PublicKey publicKey) {
        try {
            ECPublicKey ecPublicKey = (ECPublicKey) publicKey;
            ECPoint point = ecPublicKey.getW();
            BigInteger x = point.getAffineX();
            BigInteger y = point.getAffineY();

            byte[] xBytes = toUnsignedByteArray(x);
            byte[] yBytes = toUnsignedByteArray(y);

            // 创建非压缩格式的公钥: 0x04 + x + y
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            // 非压缩格式标识
            outputStream.write(0x04);
            outputStream.write(xBytes);
            outputStream.write(yBytes);

            byte[] uncompressedKey = outputStream.toByteArray();
            return Base64.getEncoder().encodeToString(uncompressedKey);
        } catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException("getUncompressedPublicKey error");
        }
    }

    /**
     * 去除符号位数据
     * @param value
     * @return
     */
    private static byte[] toUnsignedByteArray(BigInteger value) {
        byte[] signedBytes = value.toByteArray();
        if (signedBytes[0] == 0) {
            // 去除符号位填充的0
            byte[] unsignedBytes = new byte[signedBytes.length - 1];
            System.arraycopy(signedBytes, 1, unsignedBytes, 0, unsignedBytes.length);
            return unsignedBytes;
        }
        return signedBytes;
    }

    /**
     * 使用非压缩格式公钥计算共享密钥
     * @param privateKey 服务端的私钥
     * @param uncompressedPublicKeyBase64 客户端的非压缩格式公钥(Base64编码)
     * @return 公钥
     */
    public static PublicKey loadUncompressedPublicKeyFromBase64(PrivateKey privateKey, String uncompressedPublicKeyBase64) {
        try {
            // 解码Base64字符串
            byte[] uncompressedKeyBytes = Base64.getDecoder().decode(uncompressedPublicKeyBase64);

            // 验证非压缩公钥格式 (应为65字节: 0x04 + 32字节X + 32字节Y)
            if (uncompressedKeyBytes.length != 65 || uncompressedKeyBytes[0] != 0x04) {
                throw new IllegalArgumentException("无效的非压缩公钥格式");
            }

            // 提取X和Y坐标
            byte[] xBytes = new byte[32];
            byte[] yBytes = new byte[32];
            System.arraycopy(uncompressedKeyBytes, 1, xBytes, 0, 32);
            System.arraycopy(uncompressedKeyBytes, 33, yBytes, 0, 32);

            BigInteger x = new BigInteger(1, xBytes);
            BigInteger y = new BigInteger(1, yBytes);

            // 创建EC公钥规格
            ECParameterSpec ecParameters = ((ECPrivateKey) privateKey).getParams();
            ECPoint point = new ECPoint(x, y);
            ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(point, ecParameters);

            // 生成EC公钥
            KeyFactory keyFactory = KeyFactory.getInstance("EC");
            return keyFactory.generatePublic(pubKeySpec);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("loadUncompressedPublicKeyFromBase64 error");
        }
    }

}
